/*
 * All rights Reserved, Designed By www.goldbeacon.cn
 * @Title:  demo-springboot
 * @Package com.chenzhengrong.demospringboot.aop
 * @author: chenzhengrong
 * @date:   2022/8/19 9:52
 * @version V1.0
 * Copyright © 2022 www.goldbeacon.cn. All Rights Reserved.
 * 注意：本内容仅限于湖南金烽信息科技有限公司内部传阅，禁止外泄以及用于其他的商业目
 */
package com.chenzhengrong.demospringboot.aop;

import com.alibaba.fastjson.JSON;
import com.chenzhengrong.demospringboot.annotation.Log;
import com.chenzhengrong.demospringboot.domain.dto.OperateLogDTO;
import com.chenzhengrong.demospringboot.queue.OperateQueue;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * @author chenzhengrong
 * @title: LogAspect
 * @description: 日志切面类
 * @date 2022/8/19 9:52
 */
@Component
@Aspect
@Slf4j
public class LogAspect {

    @Autowired
    private OperateQueue operateQueue;

    @Pointcut("@annotation(com.chenzhengrong.demospringboot.annotation.Log)")
    public void logPoint() {
    }

    @Around("logPoint()")
    public Object doAround(ProceedingJoinPoint joinPoint) {

        long startTime = System.currentTimeMillis();

        String requestUrl = "";
        String requestMethod = "";
        String requestAddr = "";
        String requestToken = "";

        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            assert attributes != null;
            HttpServletRequest request = attributes.getRequest();
            requestUrl = request.getRequestURL().toString();
            requestMethod = request.getMethod();
            requestAddr = request.getRemoteAddr();
            requestToken = request.getHeader("sso-token");
        } catch (Exception e) {
            log.warn("获取http请求中的属性出错", e);
        }

        /*MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        log.info("方法名：{}", signature.getMethod().getName());
        log.info("方法名：{}", (Object) signature.getParameterNames());*/

        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        Log annotationLog = method.getAnnotation(Log.class);

        String desc = annotationLog.desc();


        OperateLogDTO operateLogDTO = new OperateLogDTO();
        operateLogDTO.setType(requestMethod);
        operateLogDTO.setPath(requestUrl);
        operateLogDTO.setMethod(signature.getName());
        operateLogDTO.setContent(JSON.toJSONString(joinPoint.getArgs()));
        operateLogDTO.setDescription(desc);
        operateLogDTO.setStartTime(new Date());


        log.info("请求开始");
        log.info("请求连接 {}", requestUrl);
        log.info("接口描述 {}", desc);
        log.info("请求类型 {}", requestMethod);
        log.info("请求方法 {}.{}",signature.getDeclaringTypeName(),signature.getName());
        log.info("请求ip {}", requestAddr);
        log.info("请求入参 {}", JSON.toJSONString(joinPoint.getArgs()));
        log.info("请求token {}", requestToken);
        log.info("operateLogDTO: {}", operateLogDTO);

        Object process = null;
        try {

            process = joinPoint.proceed();

            long endTime = System.currentTimeMillis();
            // 总耗时
            long totalTime = endTime - startTime;
            log.info("方法总耗时：{}ms", totalTime);

            operateLogDTO.setTotalTime(totalTime);

        } catch (Throwable e) {
            e.printStackTrace();
        }

        operateLogDTO.setEndTime(new Date());

        operateQueue.add(operateLogDTO);

        return process;
    }

}
